//package org.qiyu.live.gateway.XssFilter;
//
//import cn.hutool.core.util.StrUtil;
//import com.alibaba.fastjson.JSONObject;
//import com.fasterxml.jackson.databind.JsonNode;
//import com.fasterxml.jackson.databind.ObjectMapper;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
//import org.springframework.cloud.gateway.filter.GatewayFilterChain;
//import org.springframework.cloud.gateway.filter.GlobalFilter;
//import org.springframework.core.Ordered;
//import org.springframework.core.io.buffer.DataBuffer;
//import org.springframework.core.io.buffer.DataBufferUtils;
//import org.springframework.http.HttpMethod;
//import org.springframework.http.HttpStatus;
//import org.springframework.http.MediaType;
//import org.springframework.http.server.reactive.ServerHttpRequest;
//import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
//import org.springframework.http.server.reactive.ServerHttpResponse;
//import org.springframework.stereotype.Component;
//import org.springframework.util.StringUtils;
//import org.springframework.web.reactive.function.server.HandlerStrategies;
//import org.springframework.web.reactive.function.server.ServerRequest;
//import org.springframework.web.server.ServerWebExchange;
//import reactor.core.publisher.Flux;
//import reactor.core.publisher.Mono;
//
//import java.io.IOException;
//import java.nio.charset.StandardCharsets;
//import java.util.Iterator;
//import java.util.Map;
//import java.util.concurrent.atomic.AtomicBoolean;
//import java.util.regex.Matcher;
//import java.util.regex.Pattern;
//
///**
// * @Author {Yangb}
// * @Date: 2023/10/30/ 10:40
// * @description 防sql注入
// */
//@Slf4j
//@Component
//@ConditionalOnProperty(value = "security.sql.enabled", havingValue = "true")
//public class SqlInjectionFilter implements GlobalFilter, Ordered {
//
//    @Autowired
//    private SqlProperties sqlProperties;
//
//    /**
//     * SQL注入正则判断
//     */
//    private static final String badStrReg = "\\b(and|or)\\b.{1,6}?(=|>|<|\\bin\\b|\\blike\\b)|\\/\\*.+?\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)";
//    /**
//     * 整体都忽略大小写
//     */
//    private static final Pattern sqlPattern = Pattern.compile(badStrReg, Pattern.CASE_INSENSITIVE);
//
//    @Override
//    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//        // 获取请求路径、请求方法、请求参数
//        ServerHttpRequest request = exchange.getRequest();
//        String requestPath = request.getPath().toString();
//        HttpMethod method = request.getMethod();
//        MediaType contentType = request.getHeaders().getContentType();
//        log.info("SqlInjectionFilter start requestPath：{}, method：{}, contentType：{}", requestPath, method, contentType);
//        // 白名单放行
//        String[] whiteListArray = sqlProperties.getExcludeUrls().toArray(new String[0]);
//        for (String path : whiteListArray) {
//            if (requestPath.startsWith(path)) {
//                log.info("SqlInjectionFilter white list：" + requestPath);
//                return chain.filter(exchange);
//            }
//        }
//        // 判断Param是否存在SQL注入
//        AtomicBoolean isSqlInjection = new AtomicBoolean(false);
//        request.getQueryParams().forEach((key, values) -> {
//            for (String value : values) {
//                if (StringUtils.hasText(value) && checkSqlInjection(value)) {
//                    isSqlInjection.set(true);
//                    return;
//                }
//            }
//        });
//        if (isSqlInjection.get()) {
//            return errorResponse(exchange.getResponse());
//        }
//        // contentType不为空，一般说明body中有参数，判断body中是否存在SQL注入，如果存在则直接返回错误信息
//        if (contentType != null) {
//            return DataBufferUtils.join(exchange.getRequest().getBody()).flatMap(dataBuffer -> {
//                // 取出body中的参数
//                byte[] bytes = new byte[dataBuffer.readableByteCount()];
//                dataBuffer.read(bytes);
//                DataBufferUtils.release(dataBuffer);
//                Flux<DataBuffer> cachedFlux = Flux.defer(() -> {
//                    DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);
//                    DataBufferUtils.retain(buffer);
//                    return Mono.just(buffer);
//                });
//                String bodyString = new String(bytes, StandardCharsets.UTF_8);
//                if (MediaType.APPLICATION_JSON.isCompatibleWith(contentType)) {
//                    if (StringUtils.hasText(bodyString) && checkJsonBody(bodyString)) {
//                        isSqlInjection.set(true);
//                    }
//                } else if (MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(contentType)) {
//                    if (StringUtils.hasText(bodyString) && checkFormUrlencoded(bodyString)) {
//                        isSqlInjection.set(true);
//                    }
//                } else if (MediaType.MULTIPART_FORM_DATA.isCompatibleWith(contentType)) {
//                    if (StringUtils.hasText(bodyString) && checkFormData(bodyString)) {
//                        isSqlInjection.set(true);
//                    }
//                }
//                //  如果存在sql注入,直接拦截请求
//                if (isSqlInjection.get()) {
//                    log.error("SqlInjectionFilter {} - [{}] 参数：{}, 包含不允许sql的关键词，请求拒绝", method, requestPath, bodyString);
//                    return errorResponse(exchange.getResponse());
//                }
//                // 重新包装ServerHttpRequest
//                ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(exchange.getRequest()) {
//                    @Override
//                    public Flux<DataBuffer> getBody() {
//                        return cachedFlux;
//                    }
//                };
//                // 用新的ServerHttpRequest改变交换对象
//                ServerWebExchange mutatedExchange = exchange.mutate().request(mutatedRequest).build();
//                // 使用默认的messageReaders读取正文字符串
//                return ServerRequest.create(mutatedExchange, HandlerStrategies.withDefaults().messageReaders()).bodyToMono(String.class).doOnNext(objectValue -> {
//                    log.info("SqlInjectionFilter end requestPath：{}, method：{}, contentType：{}", requestPath, method, contentType);
//                }).then(chain.filter(mutatedExchange));
//            });
//        }
//        log.info("SqlInjectionFilter end requestPath：{}, method：{}, contentType：{}", requestPath, method, null);
//        return chain.filter(exchange);
//    }
//
//    @Override
//    public int getOrder() {
//        return Ordered.HIGHEST_PRECEDENCE + 2;
//    }
//    /**
//     * 返回错误响应
//     *
//     * @param response 响应
//     * @return Mono<Void>
//     */
//    private Mono<Void> errorResponse(ServerHttpResponse response) {
//        response.setStatusCode(HttpStatus.BAD_REQUEST);
//        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
//        JSONObject jsonObject = new JSONObject();
//        jsonObject.put("code", HttpStatus.BAD_REQUEST.value());
//        jsonObject.put("msg", "invalid request params");
//        String body = jsonObject.toJSONString();
//        DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(StandardCharsets.UTF_8));
//        return response.writeWith(Flux.just(buffer));
//    }
//
//    /**
//     * 判断输入的字符串是否包含SQL注入
//     *
//     * @param str 输入的字符串
//     * @return 如果输入的字符串包含SQL注入，返回 true，否则返回 false。
//     */
//    private boolean checkSqlInjection(String str) {
//        str = str.toLowerCase();
//        Matcher matcher = sqlPattern.matcher(str);
//        if (matcher.find()) {
//            log.error("SqlInjectionFilter 参数[{}]中包含不允许sql的关键词", str);
//            return true;
//        }
//        return false;
//    }
//
//    /**
//     * 检测application/x-www-form-urlencoded是否包含SQL注入关键字
//     *
//     * @param bodyString 请求体
//     * @return 是否包含SQL注入关键字
//     */
//    private boolean checkFormUrlencoded(String bodyString) {
//        String[] params = bodyString.split("&");
//        for (String param : params) {
//            String[] keyValue = param.split("=");
//            if (keyValue.length == 2) {
//                // 判断是否为空
//                if (StrUtil.isBlank(keyValue[1])) {
//                    continue;
//                }
//                if (checkSqlInjection(keyValue[1])) {
//                    return true;
//                }
//            }
//        }
//        return false;
//    }
//
//    /**
//     * 检测application/json是否包含SQL注入关键字
//     *
//     * @param body 请求体
//     * @return 是否包含SQL注入关键字
//     */
//    private boolean checkJsonBody(String body) {
//        try {
//            ObjectMapper objectMapper = new ObjectMapper();
//            JsonNode rootNode = objectMapper.readTree(body);
//            return checkJsonNode(rootNode);
//        } catch (IOException e) {
//            log.error("SqlInjectionFilter Error while parsing JSON body", e);
//            return false;
//        }
//    }
//
//
//    private boolean checkJsonNode(JsonNode node) {
//        if (node.isValueNode()) {
//            return checkSqlInjection(node.asText());
//        } else if (node.isObject()) {
//            Iterator<Map.Entry<String, JsonNode>> fieldsIterator = node.fields();
//            while (fieldsIterator.hasNext()) {
//                Map.Entry<String, JsonNode> field = fieldsIterator.next();
//                // 判断是否为空
//                if (field.getValue().isNull()) {
//                    continue;
//                }
//                if (checkJsonNode(field.getValue())) {
//                    return true;
//                }
//            }
//        } else if (node.isArray()) {
//            for (JsonNode childNode : node) {
//                if (checkJsonNode(childNode)) {
//                    return true;
//                }
//            }
//        }
//        return false;
//    }
//
//    /**
//     * 检测multipart/form-data是否包含SQL注入关键字
//     *
//     * @param bodyString 请求体
//     * @return 是否包含SQL注入关键字
//     */
//    public boolean checkFormData(String bodyString) {
//        bodyString = bodyString.replaceAll("\r", "");
//        String[] parts = bodyString.split("\n");
//        for (int i = 0; i < parts.length; i++) {
//            String part = parts[i];
//
//            if (part.contains("Content-Disposition: form-data;")) {
//                // 文件类型不检测
//                if (part.contains("file")) {
//                    log.info("SqlInjectionFilter file skip");
//                    return false;
//                }
//                String value = parts[i + 2];
//                if (StrUtil.isBlank(value)) {
//                    continue;
//                }
//                if (checkSqlInjection(value)) {
//                    return true;
//                }
//            }
//        }
//        return false;
//    }
//
//
//}
